home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / HPACK78S.ZIP / archive.c < prev    next >
C/C++ Source or Header  |  1992-12-03  |  46KB  |  1,506 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                          HPACK Multi-System Archiver                        *
  4. *                          ===========================                        *
  5. *                                                                            *
  6. *                     File Archive/Dearchive Handling Routines                *
  7. *                          ARCHIVE.C  Updated 27/08/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                    and if you do so there will be....trubble.                *
  12. *               And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1989 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. #include <ctype.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #ifdef __MAC__
  22.   #include "defs.h"
  23.   #include "arcdir.h"
  24.   #include "choice.h"
  25.   #include "error.h"
  26.   #include "filesys.h"
  27.   #include "flags.h"
  28.   #include "frontend.h"
  29.   #include "hpacklib.h"
  30.   #include "hpaktext.h"
  31.   #include "system.h"
  32.   #include "tags.h"
  33.   #include "crc16.h"
  34.   #include "crypt.h"
  35.   #include "fastio.h"
  36.   #include "hpackio.h"
  37.   #include "store.h"
  38. #else
  39.   #include "defs.h"
  40.   #include "arcdir.h"
  41.   #include "choice.h"
  42.   #include "error.h"
  43.   #include "filesys.h"
  44.   #include "flags.h"
  45.   #include "frontend.h"
  46.   #include "hpacklib.h"
  47.   #include "system.h"
  48.   #include "tags.h"
  49.   #include "crc/crc16.h"
  50.   #include "crypt/crypt.h"
  51.   #include "io/fastio.h"
  52.   #include "io/hpackio.h"
  53.   #include "language/hpaktext.h"
  54.   #include "store/store.h"
  55. #endif /* __MAC__ */
  56.  
  57. /* Prototypes for compression/decompression functions */
  58.  
  59. long pack( BOOLEAN *isText, long noBytes );
  60. BOOLEAN unpack( const BOOLEAN isText, const long coprLen, const long uncoprLen );
  61.  
  62. /* Prototypes for functions in GUI.C */
  63.  
  64. void initProgressReport( const BOOLEAN fileNameTruncated, const char *oldFileName, \
  65.                          const char *fileName, const LONG fileLen );
  66. void endProgressReport( void );
  67. BOOLEAN confirmSkip( const char *str1, const char *str2, const BOOLEAN str1Filename );
  68.  
  69. #ifdef __AMIGA__
  70.  
  71. /* Prototypes for functions in AMIGA.C */
  72.  
  73. LONG storeDiskObject( const char *pathName, const FD outFD );
  74. void setIcon( const char *filePath, const TAGINFO *tagInfo, const FD srcFD );
  75. int storeComment( const FILEINFO *fileInfo, const FD outFD );
  76. void setComment( const char *filePath, const TAGINFO *tagInfo, const FD srcFD );
  77.  
  78. #endif /* __AMIGA__ */
  79. #ifdef __ARC__
  80.  
  81. /* Prototypes for functions in ARC.C */
  82.  
  83. void setFileType( const char *filePath, const WORD type );
  84.  
  85. #endif /* __ARC__ */
  86. #ifdef __MAC__
  87.  
  88. /* Prototypes for functions in MAC.C */
  89.  
  90. extern BOOLEAN doCryptOut;        /* Defined in FASTIO.C */
  91.  
  92. void setFileType( const char *filePath, const LONG type, const LONG creator );
  93. void setBackupTime( const char *filePath, const LONG timeStamp );
  94. void setCreationTime( const char *filePath, const LONG timeStamp );
  95. void setVersionNumber( const char *filePath, const BYTE versionNumber );
  96. FD openResourceFork( const char *filePath, const int mode );
  97. void closeResourceFork( const FD theFD );
  98.  
  99. #endif /* __MAC__ */
  100. #ifdef __MSDOS__
  101.  
  102. /* Prototypes for functions in MISC.ASM */
  103.  
  104. void printFilePath( const char *filePath, int padding );
  105. void getFileName( char *fileName );
  106.  
  107. #endif /* __MSDOS__ */
  108. #ifdef __OS2__
  109.  
  110. /* Prototypes for functions in OS2.C */
  111.  
  112. void setAccessTime( const char *filePath, const LONG timeStamp );
  113. void setCreationTime( const char *filePath, const LONG timeStamp );
  114. void addLongName( const char *filePath, const char *longName );
  115. LONG storeEAinfo( const BOOLEAN isFile, const char *pathName, const LONG eaSize, const FD outFD );
  116. void setEAinfo( const char *filePath, const TAGINFO *tagInfo, const FD srcFD );
  117.  
  118. #endif /* __OS2__ */
  119.  
  120. /* The following is defined in FASTIO.C */
  121.  
  122. extern int cryptMark;
  123.  
  124. /* Various defines */
  125.  
  126. #define MIN_FILESIZE    50    /* Any files of below this length are stored,
  127.                                since it is not worth trying to compress
  128.                                them */
  129.  
  130. /* A flag to indicate whether we overwrite the existing file entry at currPos
  131.    or whether we add a new one via addFileHeader().  This is set for the
  132.    FRESHEN, REPLACE, and UPDATE commands */
  133.  
  134. BOOLEAN overWriteEntry;
  135.  
  136. /* The suffix to use for a filename when we use smart overwrite */
  137.  
  138. #ifdef __ARC__
  139.   char AUTO_SUFFIX[] = "_000";
  140. #else
  141.   char AUTO_SUFFIX[] = ".000";
  142. #endif /* __ARC__ */
  143.  
  144. /****************************************************************************
  145. *                                                                            *
  146. *                                General Work Functions                        *
  147. *                                                                            *
  148. ****************************************************************************/
  149.  
  150. /* Symbolic defines used when skipping a file */
  151.  
  152. #define STR1_FILENAME    TRUE
  153. #define STR2_FILENAME    FALSE
  154.  
  155. #ifndef GUI
  156.  
  157. /* Blank out a line of text */
  158.  
  159. void blankLine( int length )
  160.     {
  161.     hputchar( '\r' );
  162.     while( length-- )
  163.         hputchar( ' ' );
  164.     hputchar( '\r' );
  165.     }
  166.  
  167. /* Blank out a block of characters */
  168.  
  169. void blankChars( int length )
  170.     {
  171.     int i;
  172.  
  173.     for( i = 0; i < length; i++ )
  174.         hputchars( '\b' );
  175.     for( i = 0; i < length; i++ )
  176.         hputchars( ' ' );
  177.     for( i = 0; i < length; i++ )
  178.         hputchars( '\b' );
  179.     }
  180.  
  181. /* Handle an idiot box - either return TRUE or FALSE to the caller, or
  182.    exit if response is FALSE */
  183.  
  184. BOOLEAN confirmAction( const char *message )
  185.     {
  186.     char ch;
  187.  
  188.     hprintf( MESG_s_YN, message );
  189.     hflush( stdout );
  190.     while( ( ch = hgetch(), ch = toupper( ch ) ) != RESPONSE_YES && \
  191.                                               ch != RESPONSE_NO );
  192.     hputchar( ch );
  193.     hputchar( '\n' );
  194.     return( ch == RESPONSE_YES );
  195.     }
  196.  
  197. void idiotBox( const char *message )
  198.     {
  199.     char ch;
  200.  
  201.     hprintf( WARN_s_CONTINUE_YN, message );
  202.     hflush( stdout );
  203.     while( ( ch = hgetch(), ch = toupper( ch ) ) != RESPONSE_YES && \
  204.                                               ch != RESPONSE_NO );
  205.     hputchar( ch );
  206.     hputchar( '\n' );
  207.     if( ch == RESPONSE_NO )
  208.         {
  209.         errorFD = IO_ERROR;    /* Make sure we don't delete archive by mistake */
  210.         error( STOPPED_AT_USER_REQUEST );
  211.         }
  212.     hputchar( '\n' );
  213.     }
  214.  
  215. /* Print dots to show the length of a file.  The most elegant way to
  216.    backspace over the dots would be to use ANSI codes, but not all systems
  217.    have ANSI drivers.  Filenames are padded out with spaces to make them
  218.    align nicely */
  219.  
  220. #if defined( __ATARI__ ) || defined( __MSDOS__ )
  221.   #define PADDING        12            /* 8.3 */
  222. #elif defined( __AMIGA__ ) || defined( __MAC__ ) || defined( __OS2__ ) || defined( __UNIX__ )
  223.   #define PADDING        16            /* Pad out to at least 16 chars */
  224. #elif defined( __ARC__ )
  225.   #define PADDING        10            /* 10-char filenames */
  226. #else
  227.   #error "Need to define filename length padding in ARCHIVE.C"
  228. #endif /* Various OS-specific defines */
  229.  
  230. static void printFileName( const char *fileName, int charsUsed, \
  231.                            const long fileSize, const BOOLEAN printDots )
  232.     {
  233.     int i, length, noDots;
  234.  
  235.     /* Quick check for no printing */
  236.     if( flags & STEALTH_MODE )
  237.         return;
  238.  
  239.     hputchar( ' ' );
  240.  
  241.     /* Determine statistics for filename.  The amount added to charsUsed
  242.        represents the length of ' ' + path + SLASH (if used) + filename with
  243.        any necessary padding added + ' '.  noDots is calculated as one dot
  244.        for every 4K (2^12) bytes of data */
  245.     for( i = strlen( fileName ); i && fileName[ i ] != SLASH; i-- );
  246. #if defined( __ATARI__ ) || defined( __MSDOS__ )
  247.     charsUsed += ( i ? i + 1 : 0 ) + PADDING + 2;
  248. #elif defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __MAC__ ) || defined( __UNIX__ )
  249.     charsUsed += ( i ? i + 1 : 0 ) + 3 + \
  250.                  ( ( strlen( fileName + i ) > PADDING ) ? strlen( fileName + i ) : PADDING );
  251. #elif defined( __OS2__ )
  252.     charsUsed += ( i ? i + 1 : 0 ) + 2 + \
  253.                  ( ( strlen( fileName + i ) > PADDING ) ? strlen( fileName + i ) : PADDING );
  254. #else
  255.     hprintf( "Need to set up handling of filename padding in ARCHIVE.C, line %d\n", __LINE__ );
  256. #endif /* OS-specific padding handling */
  257.     length = ( screenWidth - charsUsed ) > 0 ? screenWidth - charsUsed : 0;
  258.     noDots = ( int ) ( fileSize >> 12 ) > length ? length : ( int ) ( fileSize >> 12 );
  259.  
  260. #ifdef __MSDOS__
  261.     printFilePath( fileName, i );
  262. #else
  263.     hprintf( "%s", fileName );    /* Filename may contain '%' char */
  264.     for( i = strlen( fileName ); i < 16; i++ )
  265.         hputchar( ' ' );
  266.     hputchar( ' ' );        /* Always print at least one space */
  267. #endif /* __MSDOS__ */
  268.  
  269.     /* Print dots corresponding to the file length if required, otherwise
  270.        print a CRLF */
  271.     if( printDots )
  272.         {
  273.         for( i = 0; i < noDots; i++ )
  274.             hputchar( '.' );
  275.         while( i-- > 0 )
  276.             hputchar( '\b' );
  277.         }
  278.     else
  279.         hputchar( '\n' );
  280.     }
  281.  
  282. /* Confirm skipping a file */
  283.  
  284. BOOLEAN confirmSkip( const char *str1, const char *str2, const BOOLEAN str1Filename )
  285.     {
  286.     char ch;
  287.  
  288.     /* Ask user for skip choice.  Note that we use a hgetch() and not a
  289.        hgetchar(), since hgetchar() requires a CR which is spuriously echoed */
  290.     hprintf( MESG_s_s_YNA, str1, str2 );
  291.     hflush( stdout );
  292.     while( ( ch = hgetch(), ch = toupper( ch ) ) != RESPONSE_YES && \
  293.                             ch != RESPONSE_NO && ch != RESPONSE_ALL );
  294.     hputchar( ch );
  295.  
  296.     /* Blank the current line */
  297.     blankLine( screenWidth - 1 );
  298.  
  299.     if( ch == RESPONSE_NO )
  300.         {
  301.         /* Indicate file is being skipped */
  302.         hprintf( MESG_SKIPPING_s, ( str1Filename ) ? str1 : str2 );
  303.         return( TRUE );
  304.         }
  305.  
  306.     if( ch == RESPONSE_ALL )
  307.         {
  308.         /* Do an automatic "Confirm" for all following files */
  309.         if( flags & INTERACTIVE )
  310.             flags &= ~INTERACTIVE;
  311.         else
  312.             overwriteFlags |= OVERWRITE_ALL;
  313.         }
  314.  
  315.     return( FALSE );
  316.     }
  317.  
  318. #ifndef __MSDOS__
  319.  
  320. /* Get a filename from the luser */
  321.  
  322. void getFileName( char *fileName )
  323.     {
  324.     hprintf( MESG_s_ALREADY_EXISTS_ENTER_NEW_NAME, fileName );
  325.  
  326.     /* Nasty input routine - should check for illegal chars and suchlike.
  327.        Will also overflow if anyone enters more than 16K chars */
  328.     hflush( stdout );
  329.     hgets( ( char * ) mrglBuffer );
  330.     mrglBuffer[ MAX_PATH - 1 ] = '\0';
  331.     strcpy( fileName, ( char * ) mrglBuffer );
  332.  
  333.     /* Clean up screen */
  334.     blankLine( screenWidth - 1 );
  335.     }
  336. #endif /* !__MSDOS__ */
  337. #endif /* !GUI */
  338.  
  339. /* Functions to handle files which didn't extract/test properly.  At the
  340.    moment we just print a summary of any problems, we could do more
  341.    sophisticated handling such as tagging them for non-deletion on move etc.
  342.    This would entail keeping track of skipped files as well as corrupted ones */
  343.  
  344. int badFileCount;
  345.  
  346. void initBadFileInfo( void )
  347.     {
  348.     /* Reset count of bad files */
  349.     badFileCount = 0;
  350.     }
  351.  
  352. void processBadFileInfo( void )
  353.     {
  354.     if( badFileCount )
  355.         {
  356. #ifdef GUI
  357.         char string[ 10 ];
  358.  
  359.         itoa( badFileCount, string, 10 );
  360.         alert( ALERT_FILES_CORRUPTED, string );
  361. #else
  362.         if( badFileCount == 1 )
  363.             hputs( WARN_FILE_CORRUPTED );
  364.         else
  365.             hprintf( WARN_d_FILES_CORRUPTED );
  366. #endif /* GUI */
  367.         }
  368.     }
  369.  
  370. /****************************************************************************
  371. *                                                                            *
  372. *                            Extract Data from an Archive                    *
  373. *                                                                            *
  374. ****************************************************************************/
  375.  
  376. /* The following variables are visible to both extractData() and retrieveData().
  377.    This is necessary since they are useful only for retrieveData() calls to
  378.    extractData() */
  379.  
  380. BOOLEAN fileNameTruncated;        /* Whether filename has been munged for OS */
  381. char *oldFileName, *fileName;    /* Original and munged filename */
  382.  
  383. /* The following variables are needed for the create-on-write facility.  This
  384.    is necessary because the output file must be opened at the last possible
  385.    moment, when there is no more chance of it being skipped.  This avoids the
  386.    case where the output file is unnecessarily overwritten when the data is
  387.    skipped */
  388.  
  389. BOOLEAN createOnWrite = FALSE;    /* Whether file needs to be created first */
  390. char *filePath;                    /* Name of output file */
  391.  
  392. /* Possible return types after data has been extracted:  Corrupted data,
  393.    OK data, data which has been skipped since the storage/encryption mode is
  394.    unknown, and data which must be resynchronised since there was some non-
  395.    data corruption (eg in the encryption information) without the usual
  396.    "Bad data" warnings */
  397.  
  398. typedef enum { DATA_BAD, DATA_OK, DATA_SKIPPED, DATA_RESYNC } DATA_STATUS;
  399.  
  400. /* General-purpose data extraction handler */
  401.  
  402. DATA_STATUS extractData( const WORD dataInfo, const BYTE extraInfo, \
  403.                          LONG dataLen, const LONG fileLen, const BOOLEAN isFile )
  404.     {
  405.     WORD oldFlags = flags, oldXlateFlags = xlateFlags;
  406. #ifndef GUI
  407.     int charsUsed = 10;        /* Length of "Extracting" */
  408. #endif /* !GUI */
  409.     BOOLEAN dataOK = TRUE, isText;
  410.     int cryptInfoLength;
  411.     FD outputFD = IO_ERROR;
  412.  
  413.     /* Set/clear encryption status depending on whether the data needs to be
  414.        decrypted or not, or complain if no password is given for private-key
  415.        encrypted data */
  416.     if( extraInfo & EXTRA_ENCRYPTED )
  417.         if( ( dataInfo & ARCH_EXTRAINFO ) && !( flags & CRYPT ) )
  418.             {
  419.             if( isFile )
  420. #ifdef GUI
  421.                 alert( ALERT_DATA_ENCRYPTED, fileName );
  422. #else
  423.                 hprintf( MESG_DATA_IS_ENCRYPTED );
  424. #endif /* GUI */
  425.             goto skipData;
  426.             }
  427.         else
  428.             /* Reset encryption system for this block of data */
  429.             if( extraInfo & EXTRA_ENCRYPTED )
  430.                 {
  431.                 if( !cryptSetInput( dataLen, &cryptInfoLength ) )
  432.                     {
  433.                     if( isFile )
  434. #ifdef GUI
  435.                         alert( ALERT_CANNOT_PROCESS_ENCR_INFO, NULL );
  436. #else
  437.                         hprintf( MESG_CANNOT_PROCESS_ENCR_INFO );
  438. #endif /* GUI */
  439.  
  440.                     if( cryptInfoLength == 0 )
  441.                         /* Encryption info corrupted, force error recovery */
  442.                         dataOK = FALSE;
  443.                     else
  444.                         /* Can't process encryption info, skip rest of data */
  445.                         dataLen -= cryptInfoLength;
  446.  
  447.                     goto skipData;
  448.                     }
  449.  
  450.                 /* Adjust data length by length of encryption information packet */
  451.                 dataLen -= cryptInfoLength;
  452.                 }
  453.  
  454.     /* Set the appropriate translation mode if necessary.  These are
  455.        different for each OS */
  456.     if( ( flags & XLATE_OUTPUT ) && ( xlateFlags & XLATE_SMART ) )
  457.         if( dataInfo & ARCH_ISTEXT )
  458.             switch( dataInfo & ARCH_SYSTEM )
  459.                 {
  460. #if !defined( __AMIGA__ ) && !defined( __ARC__ ) && !defined( __UNIX__ )
  461.                 case OS_AMIGA:
  462.                 case OS_ARCHIMEDES:
  463.                 case OS_UNIX:
  464.                     xlateFlags = XLATE_EOL;
  465.                     initTranslationSystem( '\n' );
  466.                     break;
  467. #endif /* !( __AMIGA__ || __ARC__ || __UNIX__ ) */
  468.  
  469. /*                case OS_IBM:
  470.                     xlateFlags = XLATE_EBCDIC;
  471.                     break; */
  472.  
  473. #if !defined( __MAC__ )
  474.                 case OS_MAC:
  475.                     xlateFlags = XLATE_EOL;
  476.                     initTranslationSystem( '\r' );
  477.                     break;
  478. #endif /* !__MAC__ */
  479.  
  480. #if !defined( __ATARI__ ) && !defined( __MSDOS__ ) && !defined( __OS2__ )
  481.                 case OS_ATARI:
  482.                 case OS_MSDOS:
  483.                 case OS_OS2:
  484.                     xlateFlags = XLATE_EOL;
  485.                     initTranslationSystem( '\r' | 0x80 );
  486.                     break;
  487. #endif /* !( __ATARI__ || __MSDOS__ || __OS2__ ) */
  488.  
  489.                 case OS_PRIMOS:
  490.                     xlateFlags = XLATE_PRIME;
  491.                     break;
  492.                 }
  493.         else
  494.             /* No translation for non-text files */
  495.             xlateFlags = 0;
  496.  
  497.     if( ( dataInfo & ARCH_STORAGE ) < FORMAT_UNKNOWN )
  498.         {
  499.         if( isFile )
  500.             {
  501.             /* Create the output file if necessary.  We do this at the last
  502.                possible moment since if the data is skipped for any reason
  503.                we might (unnecessarily) overwrite an existing file */
  504.             if( createOnWrite )
  505.                 {
  506.                 if( ( outputFD = hcreat( filePath, CREAT_ATTR ) ) == IO_ERROR )
  507.                     {
  508. #ifdef GUI
  509.                     alert( ALERT_CANNOT_OPEN_DATAFILE, fileName );
  510. #else
  511.                     hprintf( MESG_CANNOT_OPEN_DATAFILE );
  512. #endif /* GUI */
  513.                     goto skipData;
  514.                     }
  515.                 errorFD = outputFD;
  516.                 setOutputFD( outputFD );
  517.  
  518.                 createOnWrite = FALSE;
  519.                 }
  520.  
  521. #ifdef GUI
  522.             initProgressReport( fileNameTruncated, oldFileName, fileName, fileLen );
  523. #else
  524.             hprintfs( MESG_EXTRACTING );
  525.             if( fileNameTruncated )
  526.                 {
  527.                 hprintfs( MESG_s_AS, oldFileName );
  528.                 charsUsed += 4 + strlen( oldFileName );
  529.                 }
  530.             printFileName( fileName, charsUsed, fileLen, choice != DISPLAY );
  531. #endif /* GUI */
  532.             }
  533.  
  534.         /* Make sure we don't print any dits during the extraction by
  535.            turning on stealth mode */
  536.         if( choice == DISPLAY || !isFile )
  537.             flags |= STEALTH_MODE;
  538.  
  539.         isText = ( dataInfo & ARCH_ISTEXT ) ? TRUE : FALSE;
  540.  
  541.         switch( dataInfo & ARCH_STORAGE )
  542.             {
  543.             case FORMAT_STORED:
  544.                 /* Don't bother with zero-length files */
  545.                 if( dataLen )
  546.                     dataOK = unstore( dataLen );
  547.                 else
  548.                     /* Can't corrupt a zero-length file */
  549.                     dataOK = TRUE;
  550.                 break;
  551.  
  552.             case FORMAT_PACKED:
  553.                 dataOK = unpack( isText, dataLen, fileLen );
  554.                 firstFile = FALSE;
  555.                 break;
  556.             }
  557.         }
  558.     else
  559.         {
  560.         if( isFile )
  561. #ifdef GUI
  562.             alert( ALERT_UNKNOWN_ARCH_METHOD, fileName );
  563. #else
  564.             hprintf( MESG_UNKNOWN_ARCHIVING_METHOD );
  565. #endif /* GUI */
  566. skipData:
  567. #ifndef GUI
  568.         if( isFile )
  569.             hprintf( MESG__SKIPPING_s, fileName );
  570. #endif /* GUI */
  571.         skipDist += dataLen;
  572.         return( !dataOK ? DATA_RESYNC : DATA_SKIPPED );
  573.         }
  574.  
  575.     /* Reset various options */
  576.     flags = oldFlags;
  577.     xlateFlags = oldXlateFlags;
  578.  
  579.     /* Close the output FD if necessary */
  580.     if( outputFD != IO_ERROR )    /* outputFD may not have been created */
  581.         hclose( outputFD );
  582.     errorFD = IO_ERROR;    /* We no longer need to delete the extracted file on error */
  583.  
  584.     return( ( DATA_STATUS ) dataOK );
  585.     }
  586.  
  587. /* Retrieve data from the archive file to a data file */
  588.  
  589. void retrieveData( FILEHDRLIST *fileInfo )
  590.     {
  591.     FILEHDR *theHeader = &fileInfo->data;
  592.     BYTE *extraInfoPtr = fileInfo->extraInfo;
  593.     char *filePtr, *suffixPtr, ch;
  594.     int iteration, i;
  595.     long auxDataLen = theHeader->auxDataLen;
  596.     DATA_STATUS dataStatus;
  597. #ifndef GUI
  598.     BOOLEAN printNL = TRUE;
  599. #endif /* !GUI */
  600.     FD dataFD;
  601.     TAGINFO tagInfo;
  602. #ifdef __UNIX__
  603.     struct utimbuf timeStamp;
  604. #endif /* __UNIX__ */
  605.  
  606.     /* Flag the fact that we've accessed the archive */
  607.     archiveChanged = TRUE;
  608.  
  609.     fileNameTruncated = FALSE;
  610.     fileName = buildInternalPath( fileInfo );
  611.     if( choice == EXTRACT )
  612.         {
  613.         filePath = buildExternalPath( fileInfo );
  614.         fileNameTruncated = isTruncated();
  615.  
  616.         /*  Make sure we don't overwrite an existing file unless the
  617.             OVERWRITE_ALL option has been specified */
  618.         if( ( dataFD = hopen( filePath, O_RDONLY | S_DENYNONE ) ) != IO_ERROR )
  619.             {
  620. #ifdef __MSDOS__
  621.             /* Check if the file corresponds to a device name */
  622.             if( sysSpecFlags & SYSPEC_CHECKSAFE )
  623.                 if( isDevice( dataFD ) )
  624.                     {
  625. #ifdef GUI
  626.                     alert( ALERT_FILE_IS_DEVICEDRVR, NULL );
  627. #else
  628.                     hprintf( OSMESG_FILE_IS_DEVICEDRVR );
  629. #endif /* GUI */
  630.                     if( !( overwriteFlags & OVERWRITE_PROMPT ) )
  631.                         {
  632.                         /* Don't extract without user intervention */
  633. #ifndef GUI
  634.                         hprintf( MESG__SKIPPING_s, fileName );
  635. #endif /* !GUI */
  636.                         skipDist += theHeader->dataLen + auxDataLen;
  637.                         hclose( dataFD );
  638.                         return;
  639.                         }
  640. #ifndef GUI
  641.                     hputchar( '\n' );
  642. #endif /* !GUI */
  643.                     }
  644. #endif /* __MSDOS__ */
  645.  
  646.             hclose( dataFD );
  647.  
  648.             if( !( overwriteFlags & OVERWRITE_ALL ) )
  649.                 {
  650.                 /* Check whether we want a forced skip of this file */
  651.                 if( overwriteFlags & OVERWRITE_NONE )
  652.                     {
  653.                     ch = RESPONSE_NO;
  654. #ifdef GUI
  655.                     alert( ALERT_NO_OVERWRITE_EXISTING, fileName );
  656. #else
  657.                     hprintf( MESG_WONT_OVERWRITE_EXISTING_s, fileName );
  658. #endif /* GUI */
  659.                     }
  660.                 else
  661.                     {
  662.                     /* Find the filename component of the filePath */
  663.                     filePtr = findFilenameStart( filePath );
  664.  
  665.                     if( overwriteFlags & OVERWRITE_SMART )
  666.                         {
  667.                         /* Find either the '.' in the filename or the end of
  668.                            the filename.  In either case we stop after
  669.                            the MAX_FILENAME - 5th char to allow room for the
  670.                            extension */
  671.                         for( i = 0; *filePtr && *filePtr != '.' && i < MAX_FILENAME - 5; \
  672.                              i++, filePtr++ );
  673.                         for( iteration = strlen( fileName ) + 1; iteration && \
  674.                              fileName[ iteration - 1 ] != SLASH; iteration-- );
  675.                         suffixPtr = fileName + iteration + i;
  676.                         if( filePtr - filePath > MAX_PATH - 5 )
  677.                             /* No room for extension, panic */
  678.                             error( PATH_s_TOO_LONG, filePath );
  679.  
  680.                         /* Now try and open a new file with a numerical
  681.                            suffix.  Increment the suffix until we can open
  682.                            the file */
  683.                         iteration = 0;
  684.                         strcpy( filePtr, AUTO_SUFFIX );
  685.                         while( ( dataFD = hopen( filePath, O_RDONLY | S_DENYNONE ) ) != IO_ERROR )
  686.                             {
  687.                             hclose( dataFD );
  688.  
  689.                             /* Set the suffix to the iteration count */
  690.                             strcpy( filePtr, AUTO_SUFFIX );
  691.                             i = iteration++;
  692.                             filePtr[ 1 ] += i / 100;
  693.                             i %= 100;
  694.                             filePtr[ 2 ] += i / 10;
  695.                             i %= 10;
  696.                             filePtr[ 3 ] += i;
  697.                             }
  698.  
  699.                         /* Finally, update the fileName to reflect the changes
  700.                            to the filePath */
  701.                         strcpy( suffixPtr, filePtr );
  702.  
  703.                         /* We have now found a unique filename which we can use */
  704.                         fileNameTruncated = TRUE;    /* Force printing of original name */
  705.                         ch = RESPONSE_YES;
  706.                         }
  707.                     else
  708.                         if( overwriteFlags & OVERWRITE_PROMPT )
  709.                             {
  710.                             while( ( dataFD = hopen( filePath, O_RDONLY | S_DENYNONE ) ) != IO_ERROR )
  711.                                 {
  712.                                 hclose( dataFD );
  713.  
  714.                                 /* Call B&D filename input routine */
  715.                                 getFileName( fileName );
  716.  
  717.                                 /* Do a path length check */
  718.                                 i = MAX_PATH - strlen( filePath ) - 1;    /* -1 is for '\0' */
  719.                                 if( strlen( fileName ) > i )
  720.                                     {
  721.                                     /* Path too long, truncate and issue warning */
  722.                                     strncpy( filePtr, fileName, i );
  723.                                     filePtr[ i ] = '\0';
  724. #ifdef GUI
  725.                                     alert( ALERT_PATH_TOO_LONG, filePath );
  726. #else
  727.                                     hprintf( MESG_PATH_s__TOO_LONG, filePath );
  728. #endif /* GUI */
  729.                                     }
  730.                                 else
  731.                                     /* Copy name across */
  732.                                     strcpy( filePtr, fileName );
  733.                                 }
  734.                             fileNameTruncated = TRUE;    /* Force printing of original name */
  735.                             ch = RESPONSE_YES;
  736.                             }
  737.                         else
  738.                             ch = ( confirmSkip( filePath, MESG_ALREADY_EXISTS__OVERWRITE, \
  739.                                                 STR1_FILENAME ) ) ? RESPONSE_NO : RESPONSE_YES;
  740.                     }
  741.  
  742.                 if( ch == RESPONSE_NO )
  743.                     {
  744.                     skipDist += theHeader->dataLen + auxDataLen;
  745.                     return;
  746.                     }
  747.                 }
  748.             }
  749.         else
  750.             if( flags & INTERACTIVE )
  751.                 /* Ask the user whether they want to extract this file */
  752.                 if( confirmSkip( MESG_EXTRACT, fileName, STR2_FILENAME ) )
  753.                     {
  754.                     skipDist += theHeader->dataLen + auxDataLen;
  755.                     return;
  756.                     }
  757.  
  758.         /* Flag the fact that the file must be created when we're ready to
  759.            write to it */
  760.         createOnWrite = TRUE;
  761.  
  762.         if( fileNameTruncated )
  763.             oldFileName = fileInfo->fileName;
  764.  
  765.         /* Set the file to delete in case of error to the unarchived file */
  766.         strcpy( errorFileName, filePath );
  767.         }
  768.     else
  769.         {
  770.         if( flags & INTERACTIVE )
  771.             /* Ask the user whether they want to handle this file */
  772.             if( confirmSkip( ( choice == DISPLAY ) ? MESG_DISPLAY : MESG_TEST, \
  773.                              fileName, STR2_FILENAME ) )
  774.                 {
  775.                 skipDist += theHeader->dataLen + auxDataLen;
  776.                 return;
  777.                 }
  778.  
  779.         setOutputFD( STDOUT );
  780.         if( choice == TEST )
  781.             setOutputIntercept( OUT_NONE );
  782.         }
  783.  
  784.     /* Extract the data */
  785.     dataStatus = extractData( theHeader->archiveInfo, \
  786.                               ( extraInfoPtr == NULL ) ? 0 : *extraInfoPtr, \
  787.                               theHeader->dataLen, theHeader->fileLen, TRUE );
  788.  
  789.     /* Check the file has not been corrupted */
  790.     if( dataStatus == DATA_BAD )
  791.         {
  792.         /* A klane korruption.... */
  793. #ifdef GUI
  794.         alert( ALERT_DATA_CORRUPTED, NULL );
  795. #else
  796.         hprintf( WARN_FILE_PROBABLY_CORRUPTED );
  797. #endif /* GUI */
  798.         badFileCount++;
  799.         }
  800.  
  801.     if( choice == EXTRACT || choice == TEST )
  802.         {
  803. #ifndef GUI
  804.         if( choice == TEST && dataStatus == DATA_OK )
  805.             hprintf( MESG_FILE_TESTED_OK );
  806. #endif /* GUI */
  807.  
  808.         /* Perform a data authentication check if necessary */
  809.         if( ( theHeader->archiveInfo & ARCH_EXTRAINFO ) && \
  810.             ( *extraInfoPtr & EXTRA_SECURED ) && ( dataStatus == DATA_OK ) )
  811.             {
  812. #ifndef GUI
  813.             hputchar( '\n' );
  814. #endif /* !GUI */
  815.             readTag( &auxDataLen, &tagInfo );
  816.             checkSignature( fileInfo->offset, theHeader->dataLen );
  817. #ifndef GUI
  818.             printNL = FALSE;
  819. #endif /* !GUI */
  820.             }
  821.  
  822.         if( choice == TEST )
  823.             {
  824.             resetOutputIntercept();
  825.             skipDist += auxDataLen;
  826.             }
  827.         else
  828.             {
  829.             /* Give files their real date if necessary */
  830.             if( !( flags & TOUCH_FILES ) )
  831.                 setFileTime( filePath, theHeader->fileTime );
  832.  
  833.             if( dataStatus == DATA_SKIPPED || dataStatus == DATA_RESYNC )
  834.                 {
  835.                 /* File was never extracted, remove it */
  836.                 hunlink( filePath );
  837.  
  838.                 if( dataStatus == DATA_SKIPPED )
  839.                     {
  840.                     /* Skip auxData and exit */
  841.                     skipDist += auxDataLen;
  842. #ifndef GUI
  843.                     hputchar( '\n' );
  844. #endif /* !GUI */
  845.                     return;
  846.                     }
  847.                 }
  848.  
  849. #ifdef __MAC__
  850.             /* If we're extracting a file and don't chose to restore attribute
  851.                information, we still need to grovel through the auxData field
  852.                in case a resource fork is present */
  853.             if( ( dataStatus != DATA_RESYNC ) && !( flags & STORE_ATTR ) )
  854.                 {
  855.                 /* Grovel through the auxData field looking for a RESOURCE_FORK tag */
  856.                 while( auxDataLen > 0 )
  857.                     if( ( readTag( &auxDataLen, &tagInfo ) == TAGCLASS_MISC ) && \
  858.                         ( tagInfo.tagID == TAG_RESOURCE_FORK ) )
  859.                         /* Extract the resource data.  If we get an error,
  860.                            move to DATA_RESYNC state.  Maybe we should remove
  861.                            the file as well */
  862.                         switch( tagInfo.dataFormat )
  863.                             {
  864.                             case TAGFORMAT_STORED:
  865.                                 if( !unstore( tagInfo.dataLength ) )
  866.                                     auxDataLen = ERROR;
  867.                                 break;
  868.  
  869.                             case TAGFORMAT_PACKED:
  870.                                 if( !unpack( FALSE, tagInfo.dataLength, tagInfo.uncoprLength ) )
  871.                                     auxDataLen = ERROR;
  872.                                 break;
  873.  
  874.                             default:
  875.                                 skipSeek( tagInfo.dataLength );
  876.                             }
  877.                         else
  878.                             skipSeek( tagInfo.dataLength );
  879.                 }
  880.             else
  881. #endif /* __MAC__ */
  882.  
  883.             /* Set the files' attributes etc properly if there is any extra
  884.                information recorded */
  885.             if( ( dataStatus != DATA_RESYNC ) && ( flags & STORE_ATTR ) )
  886.                 {
  887.                 /* Grovel through the auxData field looking for tags we
  888.                    can use */
  889.                 while( auxDataLen > 0 )
  890.                     switch( readTag( &auxDataLen, &tagInfo ) )
  891.                         {
  892.                         case TAGCLASS_ATTRIBUTE:
  893.                             /* Read in the attributes and set them */
  894.                             hchmod( filePath, readAttributeData( tagInfo.tagID ) );
  895.                             break;
  896.  
  897. #if defined( __MSDOS__ )
  898.                         /* Fix compiler bug */
  899. #elif defined( __AMIGA__ )
  900.                         case TAGCLASS_ICON:
  901.                             /* Check if it's an AMIGA_ICON tag */
  902.                             if( tagInfo.tagID == TAG_AMIGA_ICON )
  903.                                 /* Set icon for file */
  904.                                 setIcon( filePath, &tagInfo, archiveFD );
  905.                             else
  906.                                 skipSeek( tagInfo.dataLength );
  907.                             break;
  908.  
  909.                         case TAGCLASS_COMMENT:
  910.                             setComment( filePath, &tagInfo, archiveFD );
  911.                             break;
  912. #elif defined( __MAC__ )
  913.                         case TAGCLASS_TIME:
  914.                             /* Read in the file times and set them */
  915.                             if( tagInfo.tagID == TAG_BACKUP_TIME )
  916.                                 /* Set file's backup time */
  917.                                 setBackupTime( filePath, fgetLong() );
  918.                             else
  919.                                 if( tagInfo.tagID == TAG_CREATION_TIME )
  920.                                     /* Set file's creation time */
  921.                                     setCreationTime( filePath, fgetLong() );
  922.                                 else
  923.                                     skipSeek( tagInfo.dataLength );
  924.                             break;
  925.  
  926.                         case TAGCLASS_MISC:
  927.                             if( tagInfo.tagID == TAG_RESOURCE_FORK )
  928.                                 /* Extract the resource data.  If we get an
  929.                                    error, move to DATA_RESYNC state.  Maybe
  930.                                    we should remove the file as well */
  931.                                 switch( tagInfo.dataFormat )
  932.                                     {
  933.                                     case TAGFORMAT_STORED:
  934.                                         if( !unstore( tagInfo.dataLength ) )
  935.                                             auxDataLen = ERROR;
  936.                                         break;
  937.  
  938.                                     case TAGFORMAT_PACKED:
  939.                                         if( !unpack( FALSE, tagInfo.dataLength, tagInfo.uncoprLength ) )
  940.                                             auxDataLen = ERROR;
  941.                                         break;
  942.  
  943.                                     default:
  944.                                         skipSeek( tagInfo.dataLength );
  945.                                     }
  946.                             else
  947.                                 if( tagInfo.tagID == TAG_VERSION_NUMBER )
  948.                                     setVersionNumber( filePath, ( BYTE ) fgetWord() );
  949.                                 else
  950.                                     skipSeek( tagInfo.dataLength );
  951.                             break;
  952. #elif defined( __OS2__ )
  953.                         case TAGCLASS_TIME:
  954.                             /* Read in the file times and set them */
  955.                             if( tagInfo.tagID == TAG_ACCESS_TIME )
  956.                                 /* Set file's access time */
  957.                                 setAccessTime( filePath, fgetLong() );
  958.                             else
  959.                                 if( tagInfo.tagID == TAG_CREATION_TIME )
  960.                                     /* Set file's creation time */
  961.                                     setCreationTime( filePath, fgetLong() );
  962.                                 else
  963.                                     skipSeek( tagInfo.dataLength );
  964.                             break;
  965.  
  966.                         case TAGCLASS_ICON:
  967.                             /* Set the icon EA if possible */
  968.                             if( tagInfo.tagID == TAG_OS2_ICON )
  969.                                 setEAinfo( filePath, &tagInfo, archiveFD );
  970.                             else
  971.                                 skipSeek( tagInfo.dataLength );
  972.                             break;
  973.  
  974.                         case TAGCLASS_MISC:
  975.                             /* Set the longname EA if possible */
  976.                             if( tagInfo.tagID  == TAG_LONGNAME || \
  977.                                 tagInfo.tagID == TAG_OS2_MISC_EA )
  978.                                 {
  979.                                 setEAinfo( filePath, &tagInfo, archiveFD );
  980.                                 break;
  981.                                 }
  982.                             else
  983.                                 skipSeek( tagInfo.dataLength );
  984.                             break;
  985. #elif defined( __UNIX__ )
  986.                         case TAGCLASS_TIME:
  987.                             /* Read in the file times and set them */
  988.                             if( tagInfo.tagID == TAG_CREATION_TIME )
  989.                                 {
  990.                                 timeStamp.actime = fgetLong();
  991.                                 timeStamp.modtime = theHeader->fileTime;
  992.                                 utime( filePath, &timeStamp );
  993.                                 }
  994.                             else
  995.                                 skipSeek( tagInfo.dataLength );
  996.                             break;
  997. #endif /* Various OS-dependant attribute reads */
  998.  
  999.                         case TAGCLASS_NONE:
  1000.                             /* Couldn't find a tag we could do anything with,
  1001.                                and we've run out of tags */
  1002.                             break;
  1003.  
  1004.                         default:
  1005.                             /* Can't do anything with this tag, skip it */
  1006.                             skipSeek( tagInfo.dataLength );
  1007.                             break;
  1008.                         }
  1009.  
  1010.                 /* If the auxDataLen count has gone negative, the data has
  1011.                    been corrupted */
  1012.                 if( auxDataLen < 0 )
  1013.                     dataStatus = DATA_RESYNC;
  1014.                 }
  1015.             else
  1016.                 skipDist += auxDataLen;
  1017.  
  1018.             /* Set the file type for those OS's which store this */
  1019. #if defined( __MSDOS__ )
  1020.             /* Fix compiler bug */
  1021. #elif defined( __ARC__ )
  1022.             findFileType( fileInfo );
  1023.             if( fileInfo->type )
  1024.                 setFileType( filePath, fileInfo->type );
  1025. #elif defined( __IIGS__ )
  1026.             findFileType( fileInfo );
  1027.             if( fileInfo->type )
  1028.                 setFileType( filePath, fileInfo->type, fileInfo->auxType );
  1029. #elif defined( __MAC__ )
  1030.             findFileType( fileInfo );
  1031.             if( fileInfo->type )
  1032.                 setFileType( filePath, fileInfo->type, fileInfo->creator );
  1033. #endif /* Various OS-dependant file-type settings */
  1034.  
  1035. #ifdef __OS2__
  1036.             /* If we've truncated the filename, add the full name as an EA */
  1037.             if( fileNameTruncated )
  1038.                 addLongName( filePath, oldFileName );
  1039. #endif /* __OS2__ */
  1040.             }
  1041.         }
  1042.     else
  1043.         {
  1044. #ifndef GUI
  1045.         hprintf( MESG_HIT_A_KEY );
  1046.         hflush( stdout );
  1047.         hgetch();    /* getchar() only terminates on CR */
  1048. #endif /* GUI */
  1049.         skipDist += auxDataLen;
  1050.         }
  1051.  
  1052. #ifdef GUI
  1053.     endProgressReport();
  1054. #else
  1055.     if( printNL )
  1056.         hputchars( '\n' );
  1057. #endif /* GUI */
  1058.  
  1059.     /* Attempt recovery if the data was corrupted */
  1060.     if( ( dataStatus == DATA_BAD || dataStatus == DATA_RESYNC ) && \
  1061.           fileInfo->next != NULL )
  1062.         {
  1063.         /* Do an absolute seek to the start of the next data block, since we
  1064.            may currently be anywhere in the current block, and reset input
  1065.            data counters */
  1066.         vlseek( fileInfo->next->offset, SEEK_SET );
  1067.         forceRead();
  1068.         skipDist = 0L;
  1069.         }
  1070.     }
  1071.  
  1072. /****************************************************************************
  1073. *                                                                            *
  1074. *                                Add Data to an Archive                        *
  1075. *                                                                            *
  1076. ****************************************************************************/
  1077.  
  1078. /* Add data to the archive file from a data file */
  1079.  
  1080. void addData( const char *filePath, const FILEINFO *fileInfoPtr, \
  1081.               const WORD dirIndex, const FD dataFD )
  1082.     {
  1083.     FILEHDR theHeader;
  1084.     long dataLength, auxDataLen = 0L, startPosition;
  1085.     int comprMethod, i, cryptInfoLength = 0, secInfoLength;
  1086.     WORD errorTagLen, hType = TYPE_NORMAL;
  1087.     BOOLEAN isText = FALSE;
  1088.     BYTE extraInfo;
  1089. #ifdef __UNIX__
  1090.     LONG linkID = ( ( LONG ) fileInfoPtr->statInfo.st_dev << 24 ) ^ fileInfoPtr->statInfo.st_ino;
  1091. /*    BOOLEAN isLink = checkForLink( linkID );    Not used yet */
  1092. #endif /* __UNIX__ */
  1093. #ifdef __MAC__
  1094.     FD savedInFD, resourceForkFD;
  1095.     int resourceComprMethod;
  1096.     BOOLEAN cryptOutSave, dummy;
  1097.     WORD cryptFlagSave;
  1098.     LONG byteCount;
  1099.  
  1100.     /* If there's a resource fork, try and establish a FD to it */
  1101.     if( fileInfoPtr->resSize && \
  1102.         ( resourceForkFD = openResourceFork( filePath, O_RDONLY | S_DENYWR | A_SEQ ) ) == IO_ERROR )
  1103.         {
  1104. #ifdef GUI
  1105.         alert( ALERT_CANNOT_OPEN_DATAFILE, filePath );
  1106. #else
  1107.         hprintf( WARN_CANNOT_OPEN_DATAFILE_s, filePath );
  1108. #endif /* GUI */
  1109.         return;
  1110.         }
  1111. #endif /* __MAC__ */
  1112.  
  1113.     /* Flag the fact that we've made changes to the archive */
  1114.     archiveChanged = TRUE;
  1115.  
  1116. #ifdef GUI
  1117.     initProgressReport( FALSE, NULL, fileInfoPtr->fName, fileInfoPtr->fSize );
  1118. #else
  1119.     hprintfs( MESG_ADDING );
  1120.     printFileName( fileInfoPtr->fName, 6, fileInfoPtr->fSize, TRUE );
  1121. #endif /* GUI */
  1122. #ifdef __UNIX__
  1123.     /* If it's a link, don't add the data twice */
  1124. /*    if( !isLink )
  1125.         Don't do anything at the moment - need to work on ergonomics of link
  1126.         handling before this code is enabled
  1127.         { */
  1128. #endif /* __UNIX__ */
  1129.     if( cryptFlags & ( CRYPT_CKE | CRYPT_PKE ) )
  1130.         cryptInfoLength = cryptBegin( MAIN_KEY );
  1131.  
  1132.     if( fileInfoPtr->fSize )
  1133.         if( fileInfoPtr->fSize > MIN_FILESIZE && !( flags & STORE_ONLY ) )
  1134.             {
  1135.             /* Encrypt any data still in the buffer.  This is necessary since
  1136.                we may need to backtrack later on if the data is uncompressible */
  1137.             if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
  1138.                 {
  1139.                 encryptCFB( _outBuffer + cryptMark, _outByteCount - cryptMark );
  1140.                 cryptMark = _outByteCount;
  1141.                 }
  1142.  
  1143.             saveCryptState();
  1144.             comprMethod = FORMAT_PACKED;
  1145.             dataLength = pack( &isText, fileInfoPtr->fSize );
  1146.             firstFile = FALSE;
  1147.  
  1148.             /* If we've ended up expanding the data then store it instead.
  1149.                Undoing the call to pack() is particularly nasty since there
  1150.                may still be data in the buffer which is unwritten; there may
  1151.                in fact still be data in the buffer from the *previous* call to
  1152.                pack(), so we must flush the buffer before we do any seeking.
  1153.                If this is a multipart archive we don't bother since the
  1154.                complications involved if the data is spread over 15 different
  1155.                disks makes recovery distrinctly nontrivial.  Similary if we
  1156.                are in block mode we can't unwind the compressor to recover */
  1157.             if( dataLength >= fileInfoPtr->fSize && \
  1158.                 !( flags & MULTIPART_ARCH ) && \
  1159.                 !( flags & BLOCK_MODE ) )
  1160.                 {
  1161. #ifdef GUI
  1162.                 /* Redraw the progress bar */
  1163.                 endProgressReport();
  1164.                 initProgressReport( FALSE, NULL, fileInfoPtr->fName, fileInfoPtr->fSize );
  1165. #else
  1166.                 /* Go to start of line and overprint "Adding" message */
  1167.                 hputchars( '\r' );
  1168.                 hprintfs( MESG_ADDING );
  1169.                 printFileName( fileInfoPtr->fName, 6, fileInfoPtr->fSize, TRUE );
  1170. #endif /* GUI */
  1171.  
  1172.                 flushBuffer();
  1173.                 hlseek( archiveFD, -dataLength, SEEK_CUR );
  1174.                 htruncate( archiveFD );    /* Kill everything after this point */
  1175.                 hlseek( dataFD, 0L, SEEK_SET );
  1176.                 restoreCryptState();
  1177.                 goto storeData;
  1178.                 }
  1179.             }
  1180.         else
  1181.             {
  1182. storeData:
  1183.             comprMethod = FORMAT_STORED;
  1184.             dataLength = store( &isText );
  1185.             }
  1186.     else
  1187.         {
  1188.         /* Don't bother handling zero-length files */
  1189.         comprMethod = FORMAT_STORED;
  1190.         dataLength = 0L;
  1191.         }
  1192.     if( cryptFlags & ( CRYPT_CKE | CRYPT_PKE ) )
  1193.         cryptEnd();
  1194.  
  1195.     /* Sign the file if required */
  1196.     if( cryptFlags & CRYPT_SIGN )
  1197.         {
  1198.         /* Get all info to sign out of buffers */
  1199.         flushBuffer();
  1200.  
  1201.         /* Write the signature as a tag.  Since we don't know the tag length
  1202.            in advance, we use a somewhat nasty trick of relying on writeTag()
  1203.            to store the length as a byte and adding it later by or-ing it into
  1204.            the data in the output buffer.  This is safe since we've just
  1205.            flushed it */
  1206.         startPosition = getCurrPosition() - dataLength;
  1207.         writeTag( TAG_SECURITY_INFO, TAGFORMAT_STORED, 0L, 0L );
  1208.         secInfoLength = createSignature( startPosition, dataLength, signerID );
  1209.         _outBuffer[ LONG_TAGSIZE ] = secInfoLength;
  1210.         auxDataLen += LONG_TAGSIZE + sizeof( BYTE ) + secInfoLength;
  1211.         }
  1212.  
  1213.     /* Add type info for archive comments */
  1214.     if( flags & ARCH_COMMENT )
  1215.         hType = commentType;
  1216.  
  1217. #ifdef __MAC__
  1218.     /* We've stored the data fork, now store the resource fork if there is
  1219.        one.  We've already opened a FD to it at the start of the function */
  1220.     if( fileInfoPtr->resSize )
  1221.         {
  1222.         /* Encrypt any data still in output buffer and force it out to disk */
  1223.         flushBuffer();
  1224.  
  1225.         /* Turn off output encryption while we write to the temp file */
  1226.         cryptFlagSave = cryptFlags;
  1227.         cryptFlags = 0;
  1228.         cryptOutSave = doCryptOut;
  1229.         doCryptOut = FALSE;
  1230.  
  1231.         /* Open the resource fork of the file */
  1232.         savedInFD = getInputFD();
  1233.         saveOutputState();
  1234.         if( ( resourceTmpFD = hcreat( RESOURCE_TMPNAME, O_RDWR ) ) == ERROR )
  1235.             error( CANNOT_OPEN_TEMPFILE );
  1236.         setInputFD( resourceForkFD );
  1237.         setOutputFD( resourceTmpFD );
  1238.  
  1239.         if( ( fileInfoPtr->resSize > MIN_FILESIZE ) && \
  1240.             !( flags & BLOCK_MODE ) && !( flags & STORE_ONLY ) )
  1241.             {
  1242.             resourceComprMethod = TAGFORMAT_PACKED;
  1243.             byteCount = pack( &dummy, fileInfoPtr->resSize );
  1244.  
  1245.             /* If we've ended up expanding the data then store it as before */
  1246.             if( byteCount >= fileInfoPtr->resSize )
  1247.                 {
  1248. #ifdef GUI
  1249.                 /* Redraw the progress bar */
  1250.                 endProgressReport();
  1251.                 initProgressReport( FALSE, NULL, fileInfoPtr->fName, fileInfoPtr->resSize );
  1252. #else
  1253.                 /* Go to start of line and overprint "Adding" message */
  1254.                 hputchars( '\r' );
  1255.                 hprintfs( MESG_ADDING );
  1256.                 printFileName( fileInfoPtr->fName, 6, fileInfoPtr->resSize, TRUE );
  1257. #endif /* GUI */
  1258.  
  1259.                 flushBuffer();
  1260.                 hlseek( resourceTmpFD, 0L, SEEK_SET );
  1261.                 htruncate( resourceTmpFD );    /* Kill everything after this point */
  1262.                 hlseek( resourceForkFD, 0L, SEEK_SET );
  1263.                 goto storeResourceData;
  1264.                 }
  1265.             }
  1266.         else
  1267.             {
  1268. storeResourceData:
  1269.             resourceComprMethod = TAGFORMAT_STORED;
  1270.             byteCount = store( &dummy );
  1271.             }
  1272.         flushBuffer();        /* Force data out to disk */
  1273.  
  1274.         /* Reset encryption status */
  1275.         cryptFlags = cryptFlagSave;
  1276.         doCryptOut = cryptOutSave;
  1277.  
  1278.         /* Now move the data from the temp file to the archive itself */
  1279.         closeResourceFork( resourceForkFD );
  1280.         hlseek( resourceTmpFD, 0L, SEEK_SET );
  1281.         setInputFD( resourceTmpFD );
  1282.         forceRead();
  1283.         restoreOutputState();
  1284.         auxDataLen += writeTag( TAG_RESOURCE_FORK, resourceComprMethod, \
  1285.                                 byteCount, fileInfoPtr->resSize ) + \
  1286.                       byteCount;
  1287.  
  1288.         /* Copy the data across the slow way.  This is necessary to handle encryption */
  1289.         while( byteCount-- )
  1290.             fputByte( fgetByte() );
  1291.  
  1292.         /* Delete temp file and restore input stream */
  1293.         hclose( resourceTmpFD );
  1294.         resourceTmpFD = IO_ERROR;        /* Mark it as invalid */
  1295.         hunlink( RESOURCE_TMPNAME );
  1296.         setInputFD( savedInFD );
  1297.         }
  1298. #endif /* __MAC__ */
  1299.  
  1300.     /* Write the file's attributes if necessary */
  1301.     if( flags & STORE_ATTR )
  1302.         {
  1303. #if defined( __MSDOS__ )
  1304.         writeTag( TAG_MSDOS_ATTR, TAGFORMAT_STORED, LEN_MSDOS_ATTR, LEN_NONE );
  1305.         fputByte( fileInfoPtr->fAttr );            /* Save attributes */
  1306.         auxDataLen += SHORT_TAGSIZE + sizeof( BYTE );
  1307. #elif defined( __AMIGA__ )
  1308.         writeTag( TAG_AMIGA_ATTR, TAGFORMAT_STORED, LEN_AMIGA_ATTR, LEN_NONE );
  1309.         fputByte( fileInfoPtr->fAttr );            /* Save attributes */
  1310.         auxDataLen += SHORT_TAGSIZE + sizeof( BYTE );
  1311.         if( fileInfoPtr->hasComment )
  1312.             auxDataLen += storeComment( fileInfoPtr, archiveFD );
  1313.         auxDataLen += storeDiskObject( filePath, archiveFD );
  1314. #elif defined( __ARC__ )
  1315.         writeTag( TAG_ARC_ATTR, TAGFORMAT_STORED, LEN_ARC_ATTR, LEN_NONE );
  1316.         fputByte( fileInfoPtr->fAttr );            /* Save attributes */
  1317.         auxDataLen += SHORT_TAGSIZE + sizeof( BYTE );
  1318. #elif defined( __ATARI__ )
  1319.         writeTag( TAG_ATARI_ATTR, TAGFORMAT_STORED, LEN_ATARI_ATTR, LEN_NONE );
  1320.         fputByte( fileInfoPtr->fAttr );            /* Save attributes */
  1321.         auxDataLen += SHORT_TAGSIZE + sizeof( BYTE );
  1322. #elif defined( __MAC__ )
  1323.         writeTag( TAG_MAC_ATTR, TAGFORMAT_STORED, LEN_MAC_ATTR, LEN_NONE );
  1324.         fputWord( fileInfoPtr->fAttr );            /* Save attributes */
  1325.         writeTag( TAG_CREATION_TIME, TAGFORMAT_STORED, LEN_CREATION_TIME, LEN_NONE );
  1326.         fputLong( fileInfoPtr->createTime );    /* Save creation time */
  1327.         writeTag( TAG_MAC_TYPE, TAGFORMAT_STORED, LEN_MAC_TYPE, LEN_NONE );
  1328.         fputLong( fileInfoPtr->type );            /* Save file type */
  1329.         writeTag( TAG_MAC_CREATOR, TAGFORMAT_STORED, LEN_MAC_CREATOR, LEN_NONE );
  1330.         fputLong( fileInfoPtr->creator );        /* Save file creator */
  1331.         if( fileInfoPtr->backupTime )
  1332.             {
  1333.             /* Save backup time if there is one */
  1334.             writeTag( TAG_BACKUP_TIME, TAGFORMAT_STORED, LEN_BACKUP_TIME, LEN_NONE );
  1335.             fputLong( fileInfoPtr->backupTime );
  1336.             auxDataLen += SHORT_TAGSIZE + sizeof( LONG );
  1337.             }
  1338.         if( fileInfoPtr->versionNumber )
  1339.             {
  1340.             /* Save version number if there is one */
  1341.             writeTag( TAG_VERSION_NUMBER, TAGFORMAT_STORED, LEN_VERSION_NUMBER, LEN_NONE );
  1342.             fputWord( ( WORD ) fileInfoPtr->versionNumber );
  1343.             auxDataLen += SHORT_TAGSIZE + sizeof( WORD );
  1344.             }
  1345.         auxDataLen += SHORT_TAGSIZE + sizeof( WORD ) + SHORT_TAGSIZE + sizeof( LONG ) + \
  1346.                       SHORT_TAGSIZE + sizeof( LONG ) + SHORT_TAGSIZE + sizeof( LONG );
  1347. #elif defined( __OS2__ )
  1348.         if( fileInfoPtr->aTime )
  1349.             {
  1350.             /* Save access time if there is one */
  1351.             writeTag( TAG_ACCESS_TIME, TAGFORMAT_STORED, LEN_ACCESS_TIME, LEN_NONE );
  1352.             fputLong( fileInfoPtr->aTime );
  1353.             }
  1354.         if( fileInfoPtr->cTime )
  1355.             {
  1356.             /* Save creation time if there is one */
  1357.             writeTag( TAG_CREATION_TIME, TAGFORMAT_STORED, LEN_CREATION_TIME, LEN_NONE );
  1358.             fputLong( fileInfoPtr->cTime );            
  1359.             }
  1360.         auxDataLen += SHORT_TAGSIZE + sizeof( LONG ) + SHORT_TAGSIZE + sizeof( LONG );
  1361.         auxDataLen += storeEAinfo( TRUE, filePath, fileInfoPtr->eaSize, archiveFD );
  1362. #elif defined( __UNIX__ )
  1363.         writeTag( TAG_UNIX_ATTR, TAGFORMAT_STORED, LEN_UNIX_ATTR, LEN_NONE );
  1364.         fputWord( fileInfoPtr->statInfo.st_mode );    /* Save attributes */
  1365.         writeTag( TAG_ACCESS_TIME, TAGFORMAT_STORED, LEN_ACCESS_TIME, LEN_NONE );
  1366.         fputLong( fileInfoPtr->statInfo.st_atime );    /* Save access time */
  1367.         auxDataLen += SHORT_TAGSIZE + sizeof( WORD ) + SHORT_TAGSIZE + sizeof( LONG );
  1368. #endif /* Various OS-dependant attribute writes */
  1369.         }
  1370. #ifdef __UNIX__
  1371. /*        }
  1372.     else
  1373.         {
  1374.         / It's a link, set to zero-length stored file /
  1375.         fileInfoPtr->fSize = 0L;
  1376.         dataLength = 0L;
  1377.         comprMethod = FORMAT_STORED;
  1378.         } */
  1379. #endif /* __UNIX__ */
  1380.  
  1381.     /* Build the header from the file info and add it to the header list */
  1382.     theHeader.fileTime = fileInfoPtr->fTime;
  1383.     theHeader.fileLen = fileInfoPtr->fSize;
  1384.     theHeader.auxDataLen = auxDataLen;
  1385.     theHeader.dirIndex = dirIndex;
  1386.     theHeader.dataLen = dataLength + cryptInfoLength;
  1387.     theHeader.archiveInfo = ( flags & ARCH_COMMENT ) ? ARCH_SPECIAL : 0;
  1388.     theHeader.archiveInfo |= comprMethod;
  1389.     theHeader.archiveInfo |= ARCHIVE_OS;
  1390.     if( isText )
  1391.         theHeader.archiveInfo |= ARCH_ISTEXT;
  1392.  
  1393.     /* Build the extraInfo byte */
  1394.     extraInfo = ( cryptFlags & CRYPT_PKE || cryptFlags & CRYPT_CKE ) ? \
  1395.                 EXTRA_ENCRYPTED : 0;
  1396.     extraInfo |= ( cryptFlags & CRYPT_SIGN ) ? EXTRA_SECURED : 0;
  1397. #if defined( __MSDOS__ )
  1398.     /* Fix compiler bug */
  1399. #elif defined( __ARC__ )
  1400.     extraInfo |= sizeof( WORD );
  1401. #elif defined( __IIGS__ )
  1402.     extraInfo |= sizeof( WORD ) + sizeof( LONG );
  1403. #elif defined( __MAC__ )
  1404.     extraInfo |= sizeof( LONG ) + sizeof( LONG );
  1405. #endif /* Various OS-dependant extraInfo length defines */
  1406. #ifdef __UNIX__
  1407. /*    if( isLink )
  1408.         extraInfo = EXTRA_LINKED; */
  1409. #endif /* __UNIX__ */
  1410.     if( extraInfo )
  1411.         theHeader.archiveInfo |= ARCH_EXTRAINFO;
  1412.  
  1413.     /* Include the size of the error recovery tag if necessary */
  1414.     if( flags & ERROR_RECOVER )
  1415.         {
  1416.         /* Length is error ID + file header + ASCIZ filename + crc16 */
  1417.         errorTagLen = ERROR_ID_SIZE + computeHeaderSize( &theHeader, extraInfo ) + \
  1418.                       strlen( fileInfoPtr->fName ) + 1 + sizeof( WORD );
  1419.         theHeader.auxDataLen += errorTagLen;
  1420.  
  1421.         /* Nasty chicken-and-egg problem: We don't know the tag size until
  1422.            after we write it, but we need to know the auxDataLen before we
  1423.            write it, so we kludge it here */
  1424.         if( errorTagLen <= SHORT_TAGLEN )
  1425.             theHeader.auxDataLen += SHORT_TAGSIZE;
  1426.         else
  1427.             theHeader.auxDataLen += LONG_TAGSIZE + ( ( errorTagLen <= 0xFF ) ? \
  1428.                                         sizeof( BYTE ) : sizeof( WORD ) ) + \
  1429.                                     sizeof( WORD );
  1430.         }
  1431.  
  1432.     if( !overWriteEntry )
  1433.         {
  1434.         /* Add the new header and any supplementary information to the list */
  1435.         addFileHeader( &theHeader, hType, extraInfo, NO_LINK );
  1436.         }
  1437.     else
  1438.         {
  1439.         /* Overwrite the existing header at this position and update its
  1440.            extraInfo */
  1441.         fileHdrCurrPtr->data = theHeader;
  1442.         if( extraInfo )
  1443.             {
  1444.             /* Get rid of any existing extraInfo if it exists */
  1445.             if( fileHdrCurrPtr->extraInfo != NULL )
  1446.                 hfree( fileHdrCurrPtr->extraInfo );
  1447.  
  1448.             /* Now add the new extraInfo */
  1449.             if( ( fileHdrCurrPtr->extraInfo = \
  1450.                     ( BYTE * ) hmalloc( getExtraInfoLen( extraInfo ) + 1 ) ) == NULL )
  1451.                 error( OUT_OF_MEMORY );
  1452.             *fileHdrCurrPtr->extraInfo = extraInfo;
  1453.             }
  1454.         }
  1455.     fileHdrCurrPtr->tagged = TRUE;
  1456.  
  1457.     /* Add any extraInfo to the header if necessary */
  1458. #if defined( __MSDOS__ )
  1459.     /* Fix compiler bug */
  1460. #elif defined( __ARC__ )
  1461.     /* Add file type */
  1462.     fileHdrCurrPtr->type = fileInfoPtr->type;
  1463. #elif defined( __IIGS__ )
  1464.     /* Add file type and auxiliary type */
  1465.     fileHdrCurrPtr->type = fileInfoPtr->type;
  1466.     fileHdrCurrPtr->auxType = fileInfoPtr->auxType;
  1467. #elif defined( __MAC__ )
  1468.     /* Add file type and creator */
  1469.     fileHdrCurrPtr->type = fileInfoPtr->type;
  1470.     fileHdrCurrPtr->creator = fileInfoPtr->creator;
  1471. #elif defined( __UNIX__ )
  1472.     /* Add link ID (only used internally by HPACK) */
  1473.     fileHdrCurrPtr->fileLinkID = linkID;
  1474. #endif /* Various OS-dependant information additions */
  1475.  
  1476.     /* Write the error recovery tag if necessary - if used this must be the
  1477.        last tag, following the file data and auxiliary data */
  1478.     if( flags & ERROR_RECOVER )
  1479.         {
  1480.         /* First, write the error-recovery ID info */
  1481.         writeTag( TAG_ERROR, TAGFORMAT_STORED, errorTagLen, LEN_NONE );
  1482.         for( i = 0; i < ERROR_ID_SIZE; i++ )
  1483.             fputByte( ERROR_ID[ i ] );
  1484.  
  1485.         /* Then write the error-recovery info itself: file header, fileName,
  1486.            and crc16 for tag info.  Note that we can't use writeTag() for
  1487.            the file header since we have to write the individual fields for
  1488.            portability */
  1489.         checksumBegin( RESET_CHECKSUM );
  1490.         theHeader.auxDataLen -= errorTagLen;
  1491.         writeFileHeader( fileHdrCurrPtr );
  1492.         auxDataLen = strlen( fileInfoPtr->fName );
  1493.         for( i = 0; i <= auxDataLen; i++ )
  1494.             fputByte( fileInfoPtr->fName[ i ] );
  1495.         checksumEnd();
  1496.         fputWord( crc16 );
  1497.         }
  1498.  
  1499. #ifdef GUI
  1500.     endProgressReport();
  1501. #else
  1502.     hputchars( '\n' );
  1503. #endif /* GUI */
  1504.     }
  1505.  
  1506.